﻿using Artech.Core.Caching;
using Microsoft.Practices.Unity.Utility;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Artech.Common;

namespace Artech.Core.Resources
{
    public abstract class ResourceProviderBase: IResourceProvider
    {
        public bool CacheEnabled { get; private set; }
        public CacheGranularity CacheMode { get; private set; }

        public ResourceProviderBase(bool cacheEnabled, CacheGranularity cacheGranularity, Func<ICacheStore<IEnumerable<StringResourceItem>>> cacheStoreAccessor)
        {
            if (cacheEnabled)
            {
                Guard.ArgumentNotNull(cacheStoreAccessor, "cacheStoreAccessor");
                this.CacheStore = cacheStoreAccessor();
            }
            this.CacheEnabled = cacheEnabled;
            this.CacheMode = cacheGranularity;
        }

        protected virtual string CreateCacheKey(string category, string name, CultureInfo culture)
        {
            Guard.ArgumentNotNull(culture, "culture");
            switch (this.CacheMode)
            {
                case CacheGranularity.All: return string.Format("*.*.*.{0}", culture.Name.ToLower()) ;
                case CacheGranularity.Category:
                    {
                        Guard.ArgumentNotNullOrEmpty(category, "category");
                        return string.Format("*.{0}.*.{1}", category, culture.Name.ToLower());
                    }
                default:
                    {
                        Guard.ArgumentNotNullOrEmpty(category, "category");
                        Guard.ArgumentNotNullOrEmpty(name, "name");
                        return string.Format("*.{0}.{1}.{2}", category, name,culture.Name.ToLower());
                    }
            }
        }

        internal protected abstract IEnumerable<StringResourceItem> GetStringsCore(CultureInfo culture);
        internal protected abstract IEnumerable<StringResourceItem> GetStringsCore(string category, CultureInfo culture);
        internal protected abstract IEnumerable<StringResourceItem> GetStringsCore(string category, string name, CultureInfo culture);        

        public virtual bool TryGetString(string category, string name, CultureInfo culture, out string value)
        {
            StringResourceItem resourceItem;
            if (!this.CacheEnabled)
            {
                resourceItem = this.GetStringsCore(category, name, culture).FirstOrDefault();
                if (null != resourceItem)
                {
                    value = resourceItem.Value;
                    return true;
                }
                value = null;
                return false;
            }

            string key = this.CreateCacheKey(category,name,culture);
            IEnumerable<StringResourceItem> resourceItems;

            switch (this.CacheMode)
            {
                case CacheGranularity.All:
                    { 
                         resourceItems = this.CacheStore.GetData(key,()=>this.GetStringsCore(culture));
                         break;
                    }
                case CacheGranularity.Category:
                    {
                        resourceItems = this.CacheStore.GetData(key, () => this.GetStringsCore(category,culture));
                        break;
                    }
                default:
                    {
                        resourceItems = this.CacheStore.GetData(key, () => this.GetStringsCore(category,name, culture));
                        break; 
                    }
            }

            resourceItem = (from item in resourceItems
                     where item.Category == category
                        && item.Name == name 
                        && item.Culture.GetLanguage() == culture.GetLanguage()
                        && item.Culture.GetRegion() == culture.GetRegion()
                     select item).FirstOrDefault();

            if (null == resourceItem)
            {
                resourceItem = (from item in resourceItems
                         where item.Category == category
                            && item.Name == name
                            && item.Culture.GetLanguage() == culture.GetLanguage()
                            && string.IsNullOrEmpty(item.Culture.GetRegion())
                         select item).FirstOrDefault();
            }

            if (null != resourceItem)
            {
                value = resourceItem.Value;
                return true;
            }
            value = null;
            return false;
        }
        public abstract StatefulEntryCollection<StringResourceEntry> GetStringsForEdit(StringResourceSearchCriteria criteria, int pageSize, int pageIndex, ResourceEntryField orderBy, Common.SortDirection sortDirection);
        public abstract void UpdateStrings(StatefulEntryCollection<StringResourceEntry> resourceEntries);

        public ICacheStore<IEnumerable<StringResourceItem>> CacheStore { get; private set; }
    }
}
